VisDrone 数据集处理与分析详细实操指南
目录
1. 前言与环境准备
1.1 实验目标
本实操指南旨在帮助你完成 VisDrone 数据集的准备、可视化、格式转换和探索性分析。我们将使用 dronefreak/VisDrone-dataset-python-toolkit 工具包,适合无人机图像处理和目标检测任务入门学习。
1.2 技能要求
即使你是新手也能完成,只需具备:
- 基本的命令行操作能力
- 简单的 Python 知识
- 对图像处理有基础了解
1.3 环境要求清单
你需要具备以下环境:
- 操作系统: Windows 10/11 带有 WSL 2
- 编程环境: Python 3.8 (通过 Conda 安装)
- 必要软件:
- Conda (Anaconda/Miniconda)
- Git
- 文本编辑器/IDE (如 VS Code)
- Web 浏览器
2. WSL 2 环境与工具准备
2.1 确认 WSL 2 已安装并支持 GUI
步骤 1: 检查 WSL 2 状态
- 打开 Windows PowerShell 或命令提示符(管理员权限)
- 运行以下命令检查 WSL 版本:
wsl -l -v- 确保你的 Linux 发行版 (如 Ubuntu) 显示为 VERSION 2
如果尚未安装 WSL 2,请参照以下步骤:
# 在PowerShell(管理员)中运行
wsl --install步骤 2: 确认 WSLg 功能可用 较新版本的 Windows 10/11 已默认支持 WSLg,这使你可以在 WSL 2 中运行 GUI 应用程序。
2.2 安装 Miniconda 到 WSL 2
步骤 1: 打开 WSL 2 终端 在 Windows 搜索栏中输入"Ubuntu"或你安装的其他 Linux 发行版名称,打开终端。
步骤 2: 下载 Miniconda 安装脚本
wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh步骤 3: 运行安装脚本
bash Miniconda3-latest-Linux-x86_64.sh按照提示操作:
- 阅读并接受许可协议(输入"yes")
- 确认安装路径(默认为
~/miniconda3,推荐使用默认路径) - 当询问是否初始化 Miniconda 3 时,输入"yes"
步骤 4: 使更改生效 关闭并重新打开 WSL 2 终端,或运行:
source ~/.bashrc步骤 5: 验证安装
conda --version应显示已安装的 Conda 版本号。
2.3 加速配置:使用国内镜像源
配置 pip 使用国内镜像(强烈推荐)
- 创建 pip 配置目录和文件:
mkdir -p ~/.pip- 用文本编辑器创建或编辑
~/.pip/pip.conf文件:
nano ~/.pip/pip.conf- 添加以下内容:
[global]
index-url = https://pypi.tuna.tsinghua.edu.cn/simple
[install]
trusted-host = pypi.tuna.tsinghua.edu.cn- 保存文件(在 nano 中按 Ctrl+O,然后按 Enter,再按 Ctrl+X 退出)
配置 Conda 使用国内镜像(可选但推荐)
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/
conda config --set show_channel_urls yes2.4 安装系统级依赖
这些依赖对于 OpenCV 的 GUI 功能、Git 和其他工具是必需的:
sudo apt update && sudo apt upgrade -y
sudo apt install -y git protobuf-compiler libgtk2.0-dev pkg-config libavcodec-dev libavformat-dev libswscale-dev libtbb2 libtbb-dev libjpeg-dev libpng-dev libtiff-dev libdc1394-22-dev libgtk-3-dev wget unzip3. 项目环境搭建
3.1 克隆 VisDrone 工具包
步骤 1: 选择工作目录
cd ~ # 或者你希望存放项目的其他目录步骤 2: 克隆仓库
git clone https://github.com/dronefreak/VisDrone-dataset-python-toolkit.git
cd VisDrone-dataset-python-toolkit📝 提示: 当前工作目录应为
~/VisDrone-dataset-python-toolkit
3.2 创建并激活 Conda 环境
步骤 1: 创建名为 visdrone_env 的 Python 3.8 环境
conda create -n visdrone_env python=3.8 -y步骤 2: 激活环境
conda activate visdrone_env你的终端提示符前应该出现 (visdrone_env),表示环境已激活。
3.3 安装 Python 依赖包
使用配置好的国内 pip 镜像安装核心库:
pip install numpy opencv-python matplotlib tensorflow jupyter notebook pandas seaborn scikit-learn tqdm⚠️ 注意: 如果遇到依赖冲突,请尝试先卸载冲突包,例如:
bashPip uninstall typing-extensions -y然后重新运行完整的安装命令。
4. 获取 VisDrone 数据集
VisDrone 数据集包含多个任务数据集,我们主要关注目标检测任务。
4.1 官方数据集信息
数据集来源: 天津大学 AISKYEYE 团队收集的无人机航拍图像和视频数据集。
数据集下载链接:
目标检测训练集(VisDrone-DET trainset, 1.44 GB):
- 百度云: https://pan.baidu.com/s/1K-JtLnlHw98UuBDrYJvw3A
- Google Drive: https://drive.google.com/file/d/1a2oHjcEcwXP8oUF95qiwrqzACb2YlUhn/view?usp=sharing
目标检测验证集(VisDrone-DET valset, 0.07 GB):
- 百度云: https://pan.baidu.com/s/1jdK_dAxRJeF2Xi50IoML1g
- Google Drive: https://drive.google.com/file/d/1bxK5zgLn0_L8x276eKkuYA_FzwCIjb59/view?usp=sharing
目标检测测试集-开发版(VisDrone-DET testset-dev, 0.28 GB):
- 百度云: https://pan.baidu.com/s/1RdRfSWV-1IFK7aWljLU_LQ
- Google Drive: https://drive.google.com/open?id=1PFdW_VFSCfZ_sTSZAGjQdifF_Xd5mf0V
4.2 下载与解压数据集
步骤 1: 创建数据存放目录
mkdir -p ~/VisDrone_datasets
cd ~/VisDrone_datasets步骤 2: 下载数据集文件 从上述链接下载至少一个数据集(推荐训练集)。 你可以使用以下方式之一:
- 通过浏览器下载后,将文件移动到 WSL 中
- 直接在 WSL 中使用 wget 下载(如果有直接链接)
步骤 3: 解压数据集文件
unzip VisDrone2019-DET-train.zip # 解压训练集,文件名可能不同数据集结构: 解压后,你会得到一个结构如下的目录:
VisDrone2019-DET-train/
├── annotations/ # 包含.txt标注文件
└── images/ # 包含.jpg图像文件5. 创建样本数据集
为了快速测试工具包功能,我们将从完整数据集创建一个小型样本数据集。
5.1 创建样本目录结构
步骤 1: 在项目根目录创建样本目录
cd ~/VisDrone-dataset-python-toolkit # 确保在项目根目录
mkdir -p data/samples/images
mkdir -p data/samples/annotations5.2 复制样本文件
步骤 1: 选择几个样本文件 从完整数据集中选择 5-10 个图像和对应的标注文件:
# 假设完整数据集位于~/VisDrone_datasets/VisDrone2019-DET-train/
# 复制10个图像文件
ls ~/VisDrone_datasets/VisDrone2019-DET-train/images/ | head -10 | xargs -I{} cp ~/VisDrone_datasets/VisDrone2019-DET-train/images/{} data/samples/images/
# 复制对应的标注文件
ls data/samples/images/ | sed 's/\.jpg/\.txt/g' | xargs -I{} cp ~/VisDrone_datasets/VisDrone2019-DET-train/annotations/{} data/samples/annotations/步骤 2: 验证样本数据集结构
ls -l data/samples/images/
ls -l data/samples/annotations/确保图像和标注文件数量相同,且文件名(不含扩展名)一一对应。
6. 数据可视化
现在我们将创建一个脚本来可视化 VisDrone 数据,并在图像上标注目标边界框。
6.1 创建可视化脚本
步骤 1: 创建脚本文件 在项目根目录下创建 enhanced_visualize.py 文件:
nano enhanced_visualize.py步骤 2: 添加以下代码
# enhanced_visualize.py
import os
import cv2
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Rectangle
import argparse
from datetime import datetime
import time
# VisDrone类别定义 (中文)
CATEGORIES = {
0: '忽略区域', 1: '行人', 2: '人群', 3: '自行车', 4: '汽车',
5: '面包车', 6: '卡车', 7: '三轮车', 8: '遮棚三轮车',
9: '公交车', 10: '摩托车', 11: '其他'
}
def visualize_image_annotations(image_path, annotation_path, output_dir="visual_output", show_image=False):
"""
可视化单个图像及其标注,并在图像上添加统计信息。
"""
if not os.path.exists(image_path):
print(f"错误: 图像文件未找到 {image_path}")
return
if not os.path.exists(annotation_path):
print(f"错误: 标注文件未找到 {annotation_path}")
return
# 读取图像
image = cv2.imread(image_path)
image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) # Matplotlib 使用 RGB
img_h, img_w = image.shape[:2]
# 读取标注
with open(annotation_path, 'r') as f:
annotations = [line.strip().split(',') for line in f if line.strip()]
fig, ax = plt.subplots(1, figsize=(14, 10))
ax.imshow(image_rgb)
ax.axis('off') # 不显示坐标轴
obj_counts = {}
total_objs = 0
# 随机颜色映射,确保每个类别颜色不同
colors = plt.cm.get_cmap('tab20', len(CATEGORIES))
for ann in annotations:
if len(ann) < 6: continue # 跳过格式不正确的标注
x, y, w, h = int(ann[0]), int(ann[1]), int(ann[2]), int(ann[3])
category_id = int(ann[5])
# 统计各类物体
if category_id > 0: # 忽略类别0 (忽略区域)
category_name = CATEGORIES.get(category_id, f"未知类别{category_id}")
obj_counts[category_name] = obj_counts.get(category_name, 0) + 1
total_objs += 1
# 绘制边界框
rect_color = colors(category_id % len(CATEGORIES)) # 使用模运算防止索引越界
rect = Rectangle((x, y), w, h, linewidth=2, edgecolor=rect_color, facecolor='none')
ax.add_patch(rect)
# 添加类别标签
ax.text(x, y - 10, category_name, color='white', fontsize=8,
bbox=dict(facecolor=rect_color, alpha=0.7, pad=0.2))
# 在图像上添加统计信息
stats_text_lines = [f"图像: {os.path.basename(image_path)}",
f"尺寸: {img_w}x{img_h}px",
f"总检测目标数: {total_objs}"]
stats_text_lines.extend([f"- {cat}: {count}" for cat, count in sorted(obj_counts.items())])
y_offset = 20
for i, line_text in enumerate(stats_text_lines):
ax.text(10, y_offset + i * 18, line_text, color='lime', fontsize=9,
bbox=dict(facecolor='black', alpha=0.6, pad=1))
# 保存图像
if not os.path.exists(output_dir):
os.makedirs(output_dir)
output_filename = os.path.join(output_dir, f"vis_{os.path.basename(image_path)}")
plt.savefig(output_filename, bbox_inches='tight', dpi=150)
print(f"可视化结果已保存到: {output_filename}")
if show_image:
plt.show()
plt.close(fig) # 关闭图像,释放内存
def find_dataset_paths(base_data_dir):
"""尝试在给定目录下找到images和annotations子目录"""
for root, dirs, _ in os.walk(base_data_dir):
if "images" in dirs and "annotations" in dirs:
return os.path.join(root, "images"), os.path.join(root, "annotations")
print(f"错误: 在 {base_data_dir} 下未找到 'images' 和 'annotations' 目录。")
return None, None
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="VisDrone 数据集可视化工具")
parser.add_argument("--data_root", type=str, default="data", help="包含VisDrone数据集的根目录 (如 'data/VisDrone2019-DET-train' 或 'data')")
parser.add_argument("--output_vis_dir", type=str, default="visual_output", help="保存可视化结果的目录")
parser.add_argument("--max_vis_images", type=int, default=5, help="最多可视化多少张图片")
parser.add_argument("--show", action="store_true", help="是否在处理时显示每张图片")
args = parser.parse_args()
images_dir, annotations_dir = find_dataset_paths(args.data_root)
if images_dir and annotations_dir:
print(f"使用图像目录: {images_dir}")
print(f"使用标注目录: {annotations_dir}")
image_files = sorted([f for f in os.listdir(images_dir) if f.lower().endswith(('.jpg', '.png', '.jpeg'))])
processed_count = 0
for img_file in image_files:
if processed_count >= args.max_vis_images:
break
base_name = os.path.splitext(img_file)[0]
image_path = os.path.join(images_dir, img_file)
annotation_path = os.path.join(annotations_dir, f"{base_name}.txt")
print(f"\n正在处理: {img_file}...")
visualize_image_annotations(image_path, annotation_path, args.output_vis_dir, args.show)
processed_count += 1
print(f"\n可视化完成! 共处理 {processed_count} 张图片。")
else:
print("未能找到数据集路径,请检查 --data_root 参数。")步骤3: 保存脚本 在nano编辑器中按Ctrl+O然后Enter保存文件,再按Ctrl+X退出。
6.2 运行可视化脚本
运行脚本并处理样本数据
python enhanced_visualize.py --data_root data/samples --max_vis_images 5 --output_vis_dir visualizations_enhanced命令参数解释:
--data_root data/samples: 指向我们手动创建的样本数据目录--max_vis_images 5: 最多处理5张图片(可以根据样本数量调整)--output_vis_dir visualizations_enhanced: 输出目录名称
6.3 检查可视化结果
步骤1: 打开输出目录
ls -l visualizations_enhanced/步骤2: 查看可视化图像 你可以通过多种方式查看生成的图像:
- 使用WSLg的图像查看器:
eog visualizations_enhanced/vis_*.jpg # 若已安装eog (Eye of GNOME)
# 或
xdg-open visualizations_enhanced/ # 打开文件夹- 通过Windows资源管理器访问: Windows资源管理器可以直接访问WSL文件系统。在Windows地址栏输入:
\\wsl$\Ubuntu\home\你的用户名\VisDrone-dataset-python-toolkit\visualizations_enhanced这些图像应显示带有彩色边界框、类别标签和统计信息的无人机图像。
7. 数据格式转换
VisDrone 数据集使用其特定的标注格式。不同的目标检测框架可能需要不同的标注格式。
7.1 转换为 PASCAL-VOC 格式 (使用工具包自带脚本)
dronefreak/VisDrone-dataset-python-toolkit 工具包内主要包含一个用于将 VisDrone 标注转换为 PASCAL-VOC XML 格式的脚本:convertVis_to_xml.py。PASCAL-VOC 是一种广泛支持的格式。
步骤 1: 确认脚本位置 该脚本 convertVis_to_xml.py 应该位于你克隆的 VisDrone-dataset-python-toolkit 项目的根目录下。
步骤 2: (示例) 执行转换为 PASCAL-VOC 格式 你需要根据 convertVis_to_xml.py 脚本的具体用法来执行。通常,你要指定输入(VisDrone 格式的标注和图像)和输出目录。请查阅该脚本的说明或其仓库的 README 文件获取确切的命令行参数。
把训练库放到工具包的文件夹后运行命令
# 示例命令,具体请参考 convertVis_to_xml.py 的实际用法
python convertVis_to_xml.py
# (可能还需要图像路径等其他参数)8. 数据探索性分析
使用Jupyter Notebook进行数据探索分析,可视化数据分布特征。
8.1 启动Jupyter Notebook
步骤1: 确保在项目根目录
cd ~/VisDrone-dataset-python-toolkit步骤2: 启动Notebook服务器
jupyter notebook --ip=0.0.0.0 --no-browser步骤3: 访问Notebook 服务器启动后,终端将显示URL和访问令牌。复制URL(通常类似于http://127.0.0.1:8888/?token=...)到浏览器访问Jupyter界面。
8.2 创建并编写分析Notebook
步骤1: 创建新Notebook 在Jupyter界面中:
- 点击右上角的"New"按钮
- 选择"Python 3"创建新的Notebook
- 重命名为"VisDrone_EDA_Samples.ipynb"(点击顶部的"Untitled",输入新名称)
步骤2: 添加代码单元格
单元格1: 导入库和基本设置
import os
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import cv2 # OpenCV
from collections import Counter
import glob # 用于查找文件路径
import json
# Matplotlib 和 Seaborn 的美化设置
%matplotlib inline
plt.style.use('ggplot')
sns.set_palette("viridis") # 设置颜色主题
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签 (如果系统有此字体)
plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号
print("库导入完成,环境设置完毕!")单元格2: 定义类别和数据路径
# VisDrone类别定义 (与 enhanced_visualize.py 中一致)
CATEGORIES = {
0: '忽略区域', 1: '行人', 2: '人群', 3: '自行车', 4: '汽车',
5: '面包车', 6: '卡车', 7: '三轮车', 8: '遮棚三轮车',
9: '公交车', 10: '摩托车', 11: '其他'
}
# 自动查找数据集路径的函数
def find_dataset_paths_notebook(base_data_dir, subfolder_name=None):
"""在基础目录下查找images和annotations子目录"""
search_dir = base_data_dir
if subfolder_name:
search_dir = os.path.join(base_data_dir, subfolder_name)
# 首先检查直接子目录结构
images_dir = os.path.join(search_dir, "images")
annotations_dir = os.path.join(search_dir, "annotations")
if os.path.isdir(images_dir) and os.path.isdir(annotations_dir):
print(f"在 {search_dir} 直接找到数据集。")
return images_dir, annotations_dir
# 然后递归搜索
for root, dirs, _ in os.walk(search_dir):
if "images" in dirs and "annotations" in dirs:
print(f"在 {root} 找到数据集。")
return os.path.join(root, "images"), os.path.join(root, "annotations")
print(f"警告: 在 {search_dir} 下未找到 'images' 和 'annotations' 目录。")
return None, None
# 设置数据集根目录
dataset_base_dir = "data"
# 为样本数据指定subfolder_name
images_dir, annotations_dir = find_dataset_paths_notebook(dataset_base_dir, subfolder_name="samples")
print(f"图像目录: {images_dir}")
print(f"标注目录: {annotations_dir}")
# 如果未找到,可以直接指定路径
if not images_dir or not annotations_dir:
images_dir = "data/samples/images"
annotations_dir = "data/samples/annotations"
print(f"手动设置 - 图像目录: {images_dir}")
print(f"手动设置 - 标注目录: {annotations_dir}")单元格3: 加载和解析标注数据
all_annotations_data = []
if annotations_dir and os.path.exists(annotations_dir):
annotation_files = sorted(glob.glob(os.path.join(annotations_dir, "*.txt")))
print(f"找到 {len(annotation_files)} 个标注文件。")
for ann_file_path in annotation_files:
image_filename_base = os.path.splitext(os.path.basename(ann_file_path))[0]
with open(ann_file_path, 'r') as f:
for line in f:
parts = line.strip().split(',')
if len(parts) < 6: continue # 确保标注格式基本正确
try:
bbox_left = int(parts[0])
bbox_top = int(parts[1])
bbox_width = int(parts[2])
bbox_height = int(parts[3])
# score = int(parts[4]) # 根据VisDrone格式,score为1表示物体,0表示忽略
category_id = int(parts[5])
# truncation = int(parts[6])
# occlusion = int(parts[7])
# 计算面积和长宽比
area = bbox_width * bbox_height
aspect_ratio = bbox_width / bbox_height if bbox_height > 0 else 0
all_annotations_data.append({
'image_id': image_filename_base,
'category_id': category_id,
'category_name': CATEGORIES.get(category_id, f"未知{category_id}"),
'x': bbox_left,
'y': bbox_top,
'width': bbox_width,
'height': bbox_height,
'area': area,
'aspect_ratio': aspect_ratio
})
except ValueError:
print(f"警告: 解析标注行失败 {parts} in {ann_file_path}")
continue
else:
print("错误: 标注目录未找到或不存在,无法加载数据。")
# 创建DataFrame
df_annotations = pd.DataFrame(all_annotations_data)
if not df_annotations.empty:
print(f"\n成功加载 {len(df_annotations)} 条标注数据。")
print("DataFrame 前5行预览:")
display(df_annotations.head())
print("\nDataFrame 基本信息:")
df_annotations.info()
else:
print("\n未能加载任何标注数据到DataFrame。")单元格4: 目标类别分布统计与可视化
if not df_annotations.empty and 'category_name' in df_annotations.columns:
# 过滤掉"忽略区域"进行主要类别分析
df_objects_only = df_annotations[df_annotations['category_id'] != 0]
plt.figure(figsize=(12, 7))
category_counts = df_objects_only['category_name'].value_counts()
sns.barplot(x=category_counts.index, y=category_counts.values)
plt.title('数据集中各目标类别数量分布 (不含忽略区域)', fontsize=16)
plt.xlabel('目标类别', fontsize=12)
plt.ylabel('数量', fontsize=12)
plt.xticks(rotation=45, ha="right", fontsize=10)
plt.tight_layout() # 调整布局以防止标签重叠
plt.show()
print("\n各类别数量:")
print(category_counts)
else:
print("DataFrame为空或缺少'category_name'列,无法进行类别分布分析。")单元格5: 目标区域面积分布
if not df_annotations.empty and 'area' in df_annotations.columns:
# 确保df_objects_only已定义
if 'df_objects_only' not in locals():
df_objects_only = df_annotations[df_annotations['category_id'] != 0]
plt.figure(figsize=(10, 6))
# 使用对数刻度可能有助于观察广泛分布的面积
sns.histplot(df_objects_only['area'], bins=50, kde=True, log_scale=(False, True)) # Y轴对数刻度
plt.title('目标边界框面积分布', fontsize=16)
plt.xlabel('面积 (像素平方)', fontsize=12)
plt.ylabel('频数 (对数刻度)', fontsize=12)
plt.show()
print("\n面积描述性统计:")
print(df_objects_only['area'].describe())
else:
print("DataFrame为空或缺少'area'列,无法进行面积分布分析。")单元格6: 每张图像中的目标数量分布
if not df_annotations.empty and 'image_id' in df_annotations.columns:
# 确保df_objects_only已定义
if 'df_objects_only' not in locals():
df_objects_only = df_annotations[df_annotations['category_id'] != 0]
objects_per_image = df_objects_only.groupby('image_id').size()
plt.figure(figsize=(10, 6))
sns.histplot(objects_per_image, bins=30, kde=False)
plt.title('每张图像中的目标数量分布', fontsize=16)
plt.xlabel('图像中的目标数量', fontsize=12)
plt.ylabel('图像数量', fontsize=12)
plt.show()
print("\n每张图像目标数量描述性统计:")
print(objects_per_image.describe())
else:
print("DataFrame为空或缺少'image_id'列,无法进行图像目标数量分析。")单元格7: 目标边界框长宽比分布
if not df_annotations.empty and 'aspect_ratio' in df_annotations.columns:
# 确保df_objects_only已定义
if 'df_objects_only' not in locals():
df_objects_only = df_annotations[df_annotations['category_id'] != 0]
# 过滤掉极端或无效的长宽比值,例如 area=0 或 height=0 导致的长宽比为0或inf
valid_aspect_ratios = df_objects_only[(df_objects_only['aspect_ratio'] > 0) &
(df_objects_only['aspect_ratio'] < 10)]['aspect_ratio']
# 设定一个合理的上限,如10
plt.figure(figsize=(10, 6))
sns.histplot(valid_aspect_ratios, bins=50, kde=True)
plt.title('目标边界框长宽比分布 (0 < AR < 10)', fontsize=16)
plt.xlabel('长宽比 (宽度/高度)', fontsize=12)
plt.ylabel('频数', fontsize=12)
plt.show()
print("\n长宽比描述性统计:")
print(valid_aspect_ratios.describe())
else:
print("DataFrame为空或缺少'aspect_ratio'列,无法进行长宽比分析。")单元格8: 不同类别的目标尺寸比较 (箱线图)
if not df_annotations.empty and 'category_name' in df_annotations.columns and 'area' in df_annotations.columns:
# 确保df_objects_only已定义
if 'df_objects_only' not in locals():
df_objects_only = df_annotations[df_annotations['category_id'] != 0]
# 选择前6个最常见的类别,以避免图表过于拥挤
top_categories = df_objects_only['category_name'].value_counts().nlargest(6).index.tolist()
df_top_categories = df_objects_only[df_objects_only['category_name'].isin(top_categories)]
plt.figure(figsize=(14, 8))
sns.boxplot(x='category_name', y='area', data=df_top_categories)
plt.title('不同类别目标的面积分布 (箱线图)', fontsize=16)
plt.xlabel('目标类别', fontsize=12)
plt.ylabel('面积 (像素平方)', fontsize=12)
plt.yscale('log') # 对数刻度更容易看清差异
plt.xticks(rotation=45, ha="right")
plt.tight_layout()
plt.show()
else:
print("DataFrame为空或缺少必要列,无法进行类别尺寸比较分析。")单元格9: 热力图 - 目标位置分布
if not df_annotations.empty and 'x' in df_annotations.columns and 'y' in df_annotations.columns:
# 确保df_objects_only已定义
if 'df_objects_only' not in locals():
df_objects_only = df_annotations[df_annotations['category_id'] != 0]
# 创建位置热力图
plt.figure(figsize=(12, 10))
# 计算目标的中心点
df_objects_only['center_x'] = df_objects_only['x'] + df_objects_only['width'] / 2
df_objects_only['center_y'] = df_objects_only['y'] + df_objects_only['height'] / 2
# 使用KDE图显示目标位置分布
sns.kdeplot(
x=df_objects_only['center_x'],
y=df_objects_only['center_y'],
cmap="hot",
fill=True,
thresh=0,
levels=100
)
plt.title('目标位置分布热力图', fontsize=16)
plt.xlabel('图像X坐标', fontsize=12)
plt.ylabel('图像Y坐标', fontsize=12)
plt.colorbar(label='密度')
plt.show()
else:
print("DataFrame为空或缺少必要的坐标列,无法创建位置热力图。")步骤3: 运行并分析结果 依次执行每个代码单元格(点击单元格,然后按Shift+Enter或单击工具栏中的运行按钮)。
观察每个可视化结果,了解数据集的以下特性:
- 各类别对象的分布情况
- 目标尺寸(面积)的分布特征
- 每张图像中目标数量的分布
- 目标形状特征(通过长宽比)
- 不同类别目标的尺寸差异
- 目标在图像中的位置分布
9. 常见问题与解决方案
9.1 中文字体显示问题
问题: 可视化图表中的中文显示为方块或乱码。
解决方案:
- 安装中文字体包:
sudo apt install -y fonts-wqy-zenhei fonts-wqy-microhei- 更新字体缓存:
fc-cache -fv- 在代码中明确指定可用的中文字体:
plt.rcParams['font.sans-serif'] = ['WenQuanYi Zen Hei', 'WenQuanYi Micro Hei', 'SimHei', 'AR PL UMing CN']9.2 依赖冲突问题
问题: 安装Python包时出现依赖冲突错误。
解决方案:
- 创建新的干净环境:
conda create -n visdrone_new python=3.8 -y
conda activate visdrone_new- 按特定顺序安装依赖:
pip install numpy
pip install opencv-python matplotlib
pip install tensorflow jupyter notebook pandas seaborn scikit-learn tqdm9.3 内存不足问题
问题: 处理大型数据集时遇到内存不足(特别是在Jupyter Notebook中)。
解决方案:
- 分批处理数据:
# 示例:分批读取与处理
batch_size = 1000
for i in range(0, len(all_files), batch_size):
batch_files = all_files[i:i+batch_size]
# 处理这个批次
process_batch(batch_files)
# 清理内存
gc.collect()- 减少加载的数据量:
# 随机抽样10%的数据进行分析
sampled_files = random.sample(all_files, int(len(all_files) * 0.1))9.4 找不到文件或目录
问题: 脚本无法找到指定的数据集目录或文件。
解决方案:
- 使用绝对路径:
python enhanced_visualize.py --data_root ~/VisDrone_datasets/VisDrone2019-DET-train- 手动检查文件结构:
ls -la ~/VisDrone_datasets/ # 检查顶层目录
ls -la ~/VisDrone_datasets/VisDrone2019-DET-train/ # 检查子目录
find ~/VisDrone_datasets/ -name "*.jpg" | head # 检查是否有jpg文件9.5 WSLg显示问题
问题: 在WSL环境下,尝试运行需要图形界面的Python脚本(例如使用OpenCV的 cv2.imshow() 进行图像可视化)时,无法正常显示可视化窗口,或者出现类似 "cannot open display" 的错误。
解决方案:
以下是几种排查和解决WSLg显示问题的方法,建议按顺序尝试:
方法一:检查并尝试设置 DISPLAY 变量 (推荐首先尝试)
检查当前
DISPLAY值: 在你的 WSL 终端 (激活了visdrone_env的那个),检查当前的DISPLAY环境变量:bash(visdrone_env) your_user@your_machine:~$ echo $DISPLAY根据你遇到的错误,它可能会输出一个具体的IP地址和端口号,例如
172.23.176.1:0。尝试 WSLg 默认
DISPLAY值: 如果你的 Windows 10/11 版本较新,应该支持 WSLg。WSLg 通常期望DISPLAY变量设置为:0(指向 WSLg 内部的 Wayland compositor)。尝试手动设置它:bash(visdrone_env) your_user@your_machine:~$ export DISPLAY=:0测试脚本: 在同一个终端中,立即再次尝试运行你的 GUI 测试脚本 (例如
test_cv_gui.py或其他包含cv2.imshow()的可视化脚本):bash(visdrone_env) your_user@your_machine:~$ python your_gui_script.py结果判断与持久化设置:
- 如果这样可行 (脚本成功显示了图形界面):
- 这说明 WSLg 已激活,问题通过设置
DISPLAY=:0解决了。 - 为了方便,你可以将
export DISPLAY=:0添加到你的 WSL shell 配置文件中,使其在每次打开新终端时自动生效。- 如果你使用 bash (默认shell):bash
echo 'export DISPLAY=:0' >> ~/.bashrc source ~/.bashrc # 使更改立即生效或重新打开终端 - 如果你使用 zsh:bash
echo 'export DISPLAY=:0' >> ~/.zshrc source ~/.zshrc # 使更改立即生效或重新打开终端
- 如果你使用 bash (默认shell):
- 注意: 虽然 WSLg 旨在自动处理
DISPLAY变量,但在某些情况下,手动设置可能有所帮助。如果将来 WSLg 的行为发生变化,或者你使用了其他 X 服务器(如 VcXsrv 并配置了特定的 IP 地址),这个固定的设置可能会与之冲突,届时你可能需要从配置文件中移除或注释掉这一行。
- 这说明 WSLg 已激活,问题通过设置
- 如果仍然不行:继续尝试下面的方法。
- 如果这样可行 (脚本成功显示了图形界面):
方法二:确认 WSLg 基础功能是否正常
安装
x11-apps(如果尚未安装): 这个软件包包含一些简单的 X11 图形应用程序,可以用来测试基础的图形显示功能。bashsudo apt update sudo apt install -y x11-apps运行
xeyes测试:bashxeyes结果判断:
- 如果屏幕上显示了一双跟随鼠标指针移动的眼睛图标,那么 WSLg 的基础图形显示功能是正常的。问题可能更多地与你的 Python 环境、OpenCV 的 GUI 后端或其他特定于应用的配置有关。
- 如果
xeyes也不显示,或者报错,那么 WSLg 本身可能没有正确启动或配置。你需要:- 检查你的 Windows 版本是否支持 WSLg (通常需要 Windows 10 build 21364+ 或 Windows 11)。
- 确保 WSL 已更新到最新版本 (
wsl --update)。 - 检查 WSLg 的相关组件是否正常运行。
方法三:间接验证——通过文件系统查看生成的图像 如果你的脚本的主要目的是处理数据并生成图像文件(即使可视化窗口无法显示),你可以检查文件是否已按预期生成。
定位输出目录: 确定你的脚本将可视化结果保存到了哪个目录。例如,教程中提到的路径是
VisDrone-dataset-python-toolkit/visualizations_enhanced。通过 Windows 文件资源管理器访问: 在 Windows 文件资源管理器的地址栏中,输入以下格式的路径(请将
Ubuntu替换为你的WSL发行版名称,你的用户名替换为你的实际 WSL 用户名,并根据实际情况调整后续路径):\\wsl$\Ubuntu\home\你的用户名\VisDrone-dataset-python-toolkit\visualizations_enhanced或者,如果你的脚本将文件保存在WSL中挂载的Windows驱动器路径下 (例如
/mnt/c/Users/YourWindowsUser/output_images),你可以直接在Windows中导航到该路径 (C:\Users\YourWindowsUser\output_images)。检查文件: 查看该目录下是否有新生成的图像文件。这可以帮助判断脚本的核心逻辑(不包括GUI显示部分)是否在正常工作。如果文件存在且内容正确,那么问题主要集中在GUI的显示环节。
进一步排查方向 (如果以上方法均无效):
- Python OpenCV GUI 后端: 确保你安装的 OpenCV (通常是
opencv-python包) 是带有 GUI 支持的版本。opencv-python-headless版本不包含 GUI 功能。 - 虚拟环境依赖: 再次确认在
visdrone_env虚拟环境中,所有必要的依赖项(包括opencv-python)都已正确安装且版本兼容。 - Windows 防火墙或安全软件: 极少数情况下,防火墙或安全软件可能会干扰 WSLg 的通信。
- 查看详细错误信息: 当 GUI 脚本失败时,仔细阅读终端中输出的完整错误信息,它们通常会包含定位问题的关键线索。
- 重启WSL: 尝试完全关闭并重启WSL服务:在PowerShell或CMD中运行
wsl --shutdown,然后重新打开WSL终端。
10. 扩展应用与后续步骤
完成本教程后,你可以进一步探索以下方向:
10.1 处理完整数据集
步骤1: 使用完整数据集运行工具
# 可视化
python enhanced_visualize.py --data_root ~/VisDrone_datasets/VisDrone2019-DET-train --max_vis_images 20 --output_vis_dir full_visualizations
# 格式转换
python visdrone2coco.py --data_dir ~/VisDrone_datasets/VisDrone2019-DET-train --output_dir full_coco_output
python visdrone2yolo.py --data_dir ~/VisDrone_datasets/VisDrone2019-DET-train --output_dir full_yolo_output步骤2: 对完整数据集进行分析 创建新的Jupyter Notebook,使用与第8节相同的代码,但将dataset_base_dir调整为完整数据集路径。
10.2 训练目标检测模型
使用转换后的数据集训练深度学习目标检测模型。
YOLOv5示例:
# 克隆YOLOv5仓库
git clone https://github.com/ultralytics/yolov5
cd yolov5
# 安装依赖
pip install -r requirements.txt
# 创建数据配置文件 (visdrone.yaml)
# 使用我们转换的YOLO格式数据训练
python train.py --img 640 --batch 16 --epochs 50 --data visdrone.yaml --weights yolov5s.ptCOCO格式与TensorFlow Object Detection API示例: 可以参考TensorFlow官方文档,使用我们转换的COCO格式数据。
10.3 自定义数据处理工具
开发自己的脚本来扩展VisDrone工具包功能。
示例: 数据增强脚本
# data_augmentation.py
import cv2
import numpy as np
import os
import glob
from tqdm import tqdm
import imgaug.augmenters as iaa
import imgaug as ia
from imgaug.augmentables.bbs import BoundingBox, BoundingBoxesOnImage
# 定义增强序列
seq = iaa.Sequential([
iaa.Fliplr(0.5), # 水平翻转
iaa.Affine(rotate=(-10, 10)), # 旋转
iaa.AddToBrightness((-30, 30)), # 亮度变化
iaa.GaussianBlur(sigma=(0, 0.5)), # 轻微模糊
iaa.Sometimes(0.3, iaa.Rain(speed=(0.1, 0.3))) # 随机添加雨天效果,增强无人机拍摄场景多样性
])
def augment_dataset(
input_images_dir,
input_annotations_dir,
output_dir,
augmentations_per_image=3
):
"""对VisDrone数据集进行数据增强
参数:
input_images_dir: 输入图像目录
input_annotations_dir: 输入标注目录
output_dir: 输出目录
augmentations_per_image: 每张原始图像生成的增强图像数量
"""
# 创建输出目录
output_images_dir = os.path.join(output_dir, "images")
output_annotations_dir = os.path.join(output_dir, "annotations")
os.makedirs(output_images_dir, exist_ok=True)
os.makedirs(output_annotations_dir, exist_ok=True)
# 获取所有图像文件
image_files = glob.glob(os.path.join(input_images_dir, "*.jpg")) + \
glob.glob(os.path.join(input_images_dir, "*.png"))
for img_path in tqdm(image_files, desc="增强数据集"):
try:
# 读取图像
img = cv2.imread(img_path)
if img is None:
print(f"警告: 无法读取图像 {img_path}")
continue
# 获取对应的标注文件
basename = os.path.splitext(os.path.basename(img_path))[0]
ann_path = os.path.join(input_annotations_dir, f"{basename}.txt")
if not os.path.exists(ann_path):
print(f"警告: 找不到对应的标注文件 {ann_path}")
continue
# 读取标注
bboxes = []
bbox_categories = []
with open(ann_path, 'r') as f:
for line in f:
parts = line.strip().split(',')
if len(parts) >= 6: # VisDrone格式
try:
x, y, w, h = map(int, parts[:4])
category_id = int(parts[5])
# 排除忽略区域(category_id=0)或无效框
if category_id > 0 and w > 0 and h > 0:
bboxes.append(BoundingBox(x1=x, y1=y, x2=x+w, y2=y+h))
bbox_categories.append(category_id)
except (ValueError, IndexError):
continue
# 初始化BoundingBoxesOnImage对象
bbs = BoundingBoxesOnImage(bboxes, shape=img.shape)
# 生成多个增强版本
for aug_idx in range(augmentations_per_image):
# 应用数据增强
aug_img, aug_bbs = seq(image=img, bounding_boxes=bbs)
# 确保所有边界框都在图像边界内
aug_bbs = aug_bbs.remove_out_of_image().clip_out_of_image()
# 保存增强后的图像
aug_image_filename = f"{basename}_aug{aug_idx}.jpg"
aug_image_path = os.path.join(output_images_dir, aug_image_filename)
cv2.imwrite(aug_image_path, aug_img)
# 保存增强后的标注
aug_annotation_filename = f"{basename}_aug{aug_idx}.txt"
aug_annotation_path = os.path.join(output_annotations_dir, aug_annotation_filename)
with open(aug_annotation_path, 'w') as f:
valid_box_count = 0
for i, bbox in enumerate(aug_bbs.bounding_boxes):
if i >= len(bbox_categories):
break
# 取整数值
x1, y1, x2, y2 = map(int, [bbox.x1, bbox.y1, bbox.x2, bbox.y2])
w, h = x2 - x1, y2 - y1
# 排除无效框
if w <= 1 or h <= 1:
continue
# VisDrone格式:
# <bbox_left>,<bbox_top>,<bbox_width>,<bbox_height>,<score>,<object_category>,<truncation>,<occlusion>
f.write(f"{x1},{y1},{w},{h},1,{bbox_categories[i]},0,0\n")
valid_box_count += 1
if valid_box_count == 0:
# 如果没有有效框,删除这个增强样本
os.remove(aug_image_path)
os.remove(aug_annotation_path)
except Exception as e:
print(f"处理 {img_path} 时出错: {e}")
continue
print(f"数据增强完成! 增强后的数据保存在 {output_dir}")
# 示例调用
if __name__ == "__main__":
import argparse
parser = argparse.ArgumentParser(description="VisDrone数据集增强工具")
parser.add_argument("--input_dir", type=str, required=True, help="输入数据集目录")
parser.add_argument("--output_dir", type=str, required=True, help="输出增强数据集目录")
parser.add_argument("--augmentations", type=int, default=3, help="每张图像的增强版本数量")
args = parser.parse_args()
# 查找images和annotations子目录
base_dir = args.input_dir
for root, dirs, _ in os.walk(base_dir):
if "images" in dirs and "annotations" in dirs:
input_images_dir = os.path.join(root, "images")
input_annotations_dir = os.path.join(root, "annotations")
print(f"找到数据集: {root}")
augment_dataset(
input_images_dir,
input_annotations_dir,
args.output_dir,
args.augmentations
)
break
else:
print(f"错误: 在 {base_dir} 下未找到 'images' 和 'annotations' 目录结构")这个脚本可以帮助增强VisDrone数据集,通过添加旋转、翻转、亮度变化和天气效果等,提高模型的泛化能力,尤其是对无人机在各种天气条件下捕获的图像。
11. 在实际项目中的应用案例
11.1 智慧城市场景
- 使用VisDrone数据集训练道路交通监控系统
# 使用车辆与行人类别的子集生成专用数据集
def create_traffic_monitoring_subset():
import shutil
from tqdm import tqdm
source_images_dir = "data/VisDrone2019-DET-train/images"
source_annots_dir = "data/VisDrone2019-DET-train/annotations"
target_dir = "data/traffic_monitoring_subset"
# 创建目标目录
target_images_dir = os.path.join(target_dir, "images")
target_annots_dir = os.path.join(target_dir, "annotations")
os.makedirs(target_images_dir, exist_ok=True)
os.makedirs(target_annots_dir, exist_ok=True)
# 目标类别:行人(1), 人群(2), 汽车(4), 面包车(5), 卡车(6), 公交车(9)
target_categories = {1, 2, 4, 5, 6, 9}
ann_files = os.listdir(source_annots_dir)
for ann_file in tqdm(ann_files, desc="创建交通监控子集"):
ann_path = os.path.join(source_annots_dir, ann_file)
# 读取标注文件,检查是否包含目标类别
relevant_objects = 0
filtered_lines = []
with open(ann_path, 'r') as f:
for line in f:
parts = line.strip().split(',')
if len(parts) >= 6:
category_id = int(parts[5])
if category_id in target_categories:
relevant_objects += 1
filtered_lines.append(line)
# 如果图像包含至少3个相关目标,将其添加到子集
if relevant_objects >= 3:
# 复制图像
img_name = os.path.splitext(ann_file)[0] + ".jpg"
img_src = os.path.join(source_images_dir, img_name)
img_dst = os.path.join(target_images_dir, img_name)
if os.path.exists(img_src):
shutil.copy(img_src, img_dst)
# 创建过滤后的标注文件
ann_dst = os.path.join(target_annots_dir, ann_file)
with open(ann_dst, 'w') as f:
f.writelines(filtered_lines)
print(f"交通监控子集已创建在 {target_dir}")11.2 农业监测应用
- 使用VisDrone数据集训练无人机农田巡检系统
# 修改本教程中的数据集转换器,添加农田监测特定类别
def customize_for_agriculture(output_label_map_path):
"""创建农业监测的标签映射文件"""
# 原始VisDrone类别
visdrone_categories = {
0: 'ignored-regions', 1: 'pedestrian', 2: 'people', 3: 'bicycle',
4: 'car', 5: 'van', 6: 'truck', 7: 'tricycle', 8: 'awning-tricycle',
9: 'bus', 10: 'motor', 11: 'others'
}
# 为农业监测重新映射类别
agriculture_mapping = {
# 保留部分原始类别
4: 'farm-vehicle', # 原car变为farm-vehicle
5: 'trailer', # 原van变为trailer
6: 'harvester', # 原truck变为harvester
7: 'tractor', # 原tricycle变为tractor
1: 'farm-worker', # 原pedestrian变为farm-worker
10: 'irrigation-device', # 原motor变为irrigation-device
11: 'crop-anomaly' # 原others变为crop-anomaly
}
# 写入新的标签映射文件
with open(output_label_map_path, 'w') as f:
for id, name in agriculture_mapping.items():
f.write(f"item {{\n")
f.write(f" id: {id}\n")
f.write(f" name: '{name}'\n")
f.write(f"}}\n\n")
print(f"农业监测标签映射已保存至 {output_label_map_path}")
return agriculture_mapping11.3 安全监控场景
- 使用VisDrone数据集训练无人机安全巡检系统
def detect_zone_intrusion(model_path, test_image_path, restricted_zone_coords):
"""使用训练好的模型检测限制区域内的入侵行为
参数:
model_path: 训练好的目标检测模型路径
test_image_path: 测试图像路径
restricted_zone_coords: 限制区域的多边形坐标,格式为 [(x1,y1), (x2,y2), ...]
"""
import cv2
import numpy as np
import tensorflow as tf
from shapely.geometry import Point, Polygon
# 加载模型
model = tf.saved_model.load(model_path)
detect_fn = model.signatures['serving_default']
# 读取图像
image = cv2.imread(test_image_path)
image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
input_tensor = tf.convert_to_tensor([image_rgb], dtype=tf.uint8)
# 执行检测
detections = detect_fn(input_tensor)
# 处理检测结果
boxes = detections['detection_boxes'][0].numpy()
scores = detections['detection_scores'][0].numpy()
classes = detections['detection_classes'][0].numpy().astype(np.int32)
# 创建限制区域多边形
restricted_zone = Polygon(restricted_zone_coords)
# 设置检测阈值
threshold = 0.5
# 检测结果处理和可视化
h, w, _ = image.shape
intrusion_detected = False
# 绘制限制区域
zone_points = np.array(restricted_zone_coords, np.int32)
zone_points = zone_points.reshape((-1, 1, 2))
cv2.polylines(image, [zone_points], True, (0, 0, 255), 2)
for i in range(len(scores)):
if scores[i] > threshold:
# 获取实际像素坐标
box = boxes[i]
y1, x1, y2, x2 = int(box[0] * h), int(box[1] * w), int(box[2] * h), int(box[3] * w)
# 计算边界框的中心点
center_x = (x1 + x2) // 2
center_y = (y1 + y2) // 2
center_point = Point(center_x, center_y)
# 检查中心点是否在限制区域内
if restricted_zone.contains(center_point):
# 区域内入侵对象用红色显示
cv2.rectangle(image, (x1, y1), (x2, y2), (0, 0, 255), 2)
label = f"Class: {classes[i]}, Score: {scores[i]:.2f}, INTRUSION!"
cv2.putText(image, label, (x1, y1 - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 2)
intrusion_detected = True
else:
# 区域外对象用绿色显示
cv2.rectangle(image, (x1, y1), (x2, y2), (0, 255, 0), 2)
label = f"Class: {classes[i]}, Score: {scores[i]:.2f}"
cv2.putText(image, label, (x1, y1 - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)
# 在图像上显示警告状态
if intrusion_detected:
warning_text = "⚠️ INTRUSION DETECTED ⚠️"
cv2.putText(image, warning_text, (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2)
# 保存结果
result_path = test_image_path.replace('.jpg', '_intrusion_result.jpg')
cv2.imwrite(result_path, image)
print(f"结果已保存至 {result_path}")
return intrusion_detected, result_path11.4 工业应用示例
- 使用 VisDrone 数据集训练矿区安全监控系统
# 矿区无人机监控示例使用案例
def mining_site_monitoring_demo():
# 示例代码:矿区监控应用
import cv2
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Rectangle
def analyze_mining_site_image(image_path, model):
"""分析矿区航拍图像"""
# 读取图像
image = cv2.imread(image_path)
image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
# 模拟目标检测结果
# 实际应用中,这里会调用加载好的模型进行检测
detections = {
'equipment': [(150, 200, 50, 30), (300, 250, 70, 40)], # x, y, w, h
'vehicle': [(450, 300, 60, 30), (200, 400, 80, 50)],
'personnel': [(100, 150, 20, 40), (350, 180, 20, 40), (500, 350, 20, 40)]
}
# 创建可视化
plt.figure(figsize=(12, 10))
plt.imshow(image_rgb)
# 绘制检测结果
colors = {'equipment': 'blue', 'vehicle': 'green', 'personnel': 'red'}
for obj_type, boxes in detections.items():
for box in boxes:
x, y, w, h = box
rect = Rectangle((x, y), w, h, linewidth=2, edgecolor=colors[obj_type], facecolor='none')
plt.gca().add_patch(rect)
plt.text(x, y-5, obj_type, color=colors[obj_type], fontsize=10)
# 检查危险情况:人员与设备距离过近
safety_issues = []
for person_box in detections['personnel']:
px, py, pw, ph = person_box
person_center = (px + pw/2, py + ph/2)
# 检查与设备的距离
for equip_box in detections['equipment']:
ex, ey, ew, eh = equip_box
equip_center = (ex + ew/2, ey + eh/2)
# 计算距离
distance = np.sqrt((person_center[0] - equip_center[0])**2 +
(person_center[1] - equip_center[1])**2)
# 如果距离小于阈值,标记为不安全
if distance < 100: # 像素距离阈值
safety_issues.append((person_box, equip_box))
# 绘制连接线表示危险关系
plt.plot([person_center[0], equip_center[0]],
[person_center[1], equip_center[1]],
'y--', linewidth=2)
plt.title('矿区安全监控分析')
plt.axis('off')
# 添加图例
for obj_type, color in colors.items():
plt.plot([], [], color=color, label=obj_type)
if safety_issues:
plt.plot([], [], 'y--', label='安全隐患')
plt.legend()
# 保存结果
result_path = image_path.replace('.jpg', '_mining_analysis.jpg')
plt.savefig(result_path, dpi=300, bbox_inches='tight')
return {
'total_equipment': len(detections['equipment']),
'total_vehicles': len(detections['vehicle']),
'total_personnel': len(detections['personnel']),
'safety_issues': len(safety_issues),
'result_image': result_path
}
# 模拟调用分析函数
print ("模拟矿区无人机监控系统...")
Result = analyze_mining_site_image ('example_mining_site.jpg', None)
print (f"分析结果: 检测到 {result['total_equipment']} 台设备, {result['total_vehicles']} 辆车辆, "
f"{result['total_personnel']} 名人员")
print (f"发现 {result['safety_issues']} 处安全隐患")
print (f"结果图像已保存到: {result['result_image']}")12. 课程实验与报告指南
为完成林云老师布置的无人机相关作业,以下是实验步骤和报告编写指南:
12.1 实验步骤详细规划
步骤 1: 准备环境与数据集
# 配置开发环境
# 创建虚拟环境
conda create -n visdrone python=3.8 -y
conda activate visdrone
# 安装依赖
pip install opencv-python matplotlib numpy pandas seaborn scikit-learn \
Jupyter notebook tqdm tensorflow pillow imgaug shapely
# 下载 VisDrone 数据集
Mkdir -p ~/VisDrone_datasets
Cd ~/VisDrone_datasets
# 从官方网站手动下载并上传到服务器
# https://github.com/VisDrone/VisDrone-Dataset
# 解压数据集
tar -xf VisDrone 2019-DET-train.tar步骤 2: 实验流程记录
应用本教程的可视化工具:
bash# 克隆工具库 git clone https://github.com/your_username/VisDrone-dataset-python-toolkit.git Cd VisDrone-dataset-python-toolkit # 运行可视化脚本 python enhanced_visualize.py --data_root ~/VisDrone_datasets/VisDrone 2019-DET-train --max_vis_images 10格式转换演示:
bash# COCO 格式转换 python visdrone 2 coco.py --data_dir ~/VisDrone_datasets/VisDrone 2019-DET-train --output_dir coco_output # YOLO 格式转换 python visdrone 2 yolo.py --data_dir ~/VisDrone_datasets/VisDrone 2019-DET-train --output_dir yolo_output数据集统计分析:
bash# 运行 Jupyter Notebook 进行交互式分析 Jupyter notebook visdrone_analysis. Ipynb数据增强演示:
bash# 运行数据增强脚本 python data_augmentation.py --input_dir ~/VisDrone_datasets/VisDrone 2019-DET-train --output_dir augmented_data --augmentations 3
12.2 实验报告编写指南
一、引言
- 无人机图像识别技术的背景和重要性
- VisDrone 数据集介绍和特点
- 实验目标和内容概述
二、理论基础
- 目标检测算法基础
- 无人机视角下的目标检测挑战
- VisDrone 数据集标注格式解析
三、实验环境与配置
- 硬件环境
- 软件环境(系统版本、Python 版本、相关库版本)
- 数据集获取与预处理
四、数据可视化与分析
- 可视化工具实现原理
- 数据集样本展示
- 标注信息统计与分析
- 类别分布
- 目标尺寸分布
- 目标位置分布热力图
五、数据格式转换实现
- COCO 格式转换原理与实现
- YOLO 格式转换原理与实现
- 转换结果验证
六、数据增强技术应用
- 增强策略选择原理
- Imgaug 库应用方法
- 增强效果对比与展示
七、应用案例设计
- 选择一个具体应用场景(安全监控/交通监控/农业监测等)
- 应用流程设计
- 关键代码实现与解析
八、实验结果与分析
- 各工具的执行结果
- 数据集特点总结
- 应用案例效果评估
九、结论与展望
- 实验总结
- VisDrone 数据集的优缺点分析
- 未来改进方向
十、参考文献
- 格式规范的文献引用列表
12.3 录屏与演示建议
按照林云老师的要求进行完整的实验过程录屏,建议按以下几个部分进行:
环境配置录屏
- 操作系统环境展示
- Python 环境配置
- 依赖包安装
数据集预处理录屏
- 数据集下载/解压过程
- 数据集结构介绍
- 示例图像与标注展示
工具使用录屏
- 可视化工具运行过程
- 格式转换工具运行过程
- Jupyter Notebook 中的数据分析过程
应用场景演示录屏
- 选择的应用案例执行过程
- 结果展示与解释
在录屏过程中,建议:
- 使用麦克风实时解说操作步骤和原理
- 放慢关键步骤的操作速度,确保观众能够跟上
- 对遇到的错误及解决方案进行详细说明
- 在录屏结束时对整个实验过程进行总结
13. 总结与进一步学习资源
13.1 教程总结
本教程全面介绍了VisDrone数据集的处理与应用方法,包括:
- 数据集基础:详细解析了VisDrone目标检测数据集的结构、标注格式和类别定义。
- 可视化工具:提供了多种可视化方法,帮助直观理解数据集特点。
- 数据分析:通过统计分析揭示了数据集的类别分布、目标尺寸特征和密度特性。
- 格式转换:实现了从VisDrone原始格式到COCO、YOLO等主流格式的转换工具。
- 数据增强:提供了针对无人机视角特点的数据增强方法。
- 应用案例:展示了VisDrone数据集在智慧城市、安全监控和农业等领域的实际应用。
通过掌握这些工具和方法,你可以高效地利用VisDrone数据集来训练和优化目标检测模型,解决无人机视角下的各种实际问题。
13.2 进一步学习资源
为了深入研究无人机视觉领域,以下是推荐的学习资源:
学术论文
Zhu, P., Wen, L., Du, D., Bian, X., Ling, H., et al. (2020). Vision Meets Drones: Past, Present and Future. arXiv preprint arXiv:2001.06303.
Wen, L., Zhu, P., Du, D., Bian, X., et al. (2019). VisDrone-DET2019: The Vision Meets Drone Object Detection in Image Challenge Results. ICCV Workshop.
Bozcan, I., & Kalkan, S. (2021). ADDR: Anomaly Detection in Drone Recordings Using Spatio-Temporal Autoencoders. IEEE Robotics and Automation Letters.
在线课程和教程
无人机遥感与计算机视觉 - 清华大学/Stanford大学联合课程
Coursera: Aerial Robotics - 宾夕法尼亚大学 这门课程涵盖了无人机的基本原理,包括感知系统。
Udacity: Flying Car Nanodegree 包含无人机计算机视觉和感知系统的专业课程。
开源项目与代码库
MMDetection - 支持VisDrone数据集的目标检测工具箱 GitHub: open-mmlab/mmdetection
DroneVision - 无人机视觉处理框架 GitHub: VisDrone (VisDrone)
AerialDetection - 专注于航空图像目标检测的工具库 GitHub: dingjiansw101/AerialDetection
竞赛与挑战
VisDrone Challenge - 年度无人机视觉算法竞赛 网址:VisDrone Challenge
NTIRE Workshop - 经常举办无人机图像处理相关竞赛 网址:NTIRE Workshop
Kaggle - 定期举办无人机图像分析相关竞赛
数据集
UAVid - 无人机城市场景语义分割数据集 网址:UAVid
UAVDT - 无人机视角下的目标检测与跟踪数据集 网址:UAVDT
Aerial Image Dataset - 航空图像分析集合 网址:Aerial Image Dataset
13.3 实用工具推荐
LabelImg - 适用于目标检测标注的图形界面工具 GitHub: tzutalin/labelImg
CVAT - 强大的计算机视觉标注工具,支持视频和图像 GitHub: opencv/cvat
Roboflow - 提供数据集管理、增强和格式转换的在线平台 网址:Roboflow
ImgAug - 本教程中使用的图像增强库 GitHub: aleju/imgaug
Albumentations - 高性能的图像增强库 GitHub: albumentations-team/albumentations
13.4 致谢与贡献指南
感谢所有为VisDrone数据集做出贡献的研究者,特别是来自天津大学、布里斯托大学等机构的团队。本教程旨在帮助更多研究者和开发者有效利用这一宝贵资源。
如果您想为本教程做出贡献,请通过以下方式参与:
- 提交Bug报告或功能请求
- 贡献新的数据处理或可视化代码
- 分享您使用VisDrone数据集的实际应用案例
- 改进文档或添加更多教程内容
13.5 许可证信息
本教程中的代码采用MIT许可证发布,您可以自由使用、修改和分发这些代码,但需保留原始版权声明。请注意,VisDrone数据集本身有其特定的使用条款,使用前请查阅官方网站。